#include "internal.h"

static struct sched_rt_entity *pick_next_rt_entity(struct rt_rq *rt_rq)
{
    struct rt_prio_array *array = &rt_rq->active;
    struct sched_rt_entity *next = NULL;
    struct list_head *queue;
    int idx;

    idx = sched_find_first_bit(array->bitmap);
    BUG_ON(idx >= MAX_RT_PRIO);

    queue = array->queue + idx;
    if (WARN_ON_ONCE(list_empty(queue)))
        return NULL;
    next = list_entry(queue->next, struct sched_rt_entity, run_list);

    return next;
}

static struct task_struct *_pick_next_task_rt(struct rq *rq)
{
    struct sched_rt_entity *rt_se;
    struct rt_rq *rt_rq = &rq->rt;

    do
    {
        rt_se = pick_next_rt_entity(rt_rq);
        if (unlikely(!rt_se))
            return NULL;
        rt_rq = group_rt_rq(rt_se);
    } while (rt_rq);

    return rt_task_of(rt_se);
}

static struct task_struct *pick_task_rt(struct rq *rq)
{
    struct task_struct *p;

    if (!sched_rt_runnable(rq))
        return NULL;

    p = _pick_next_task_rt(rq);

    return p;
}

/***************************************************************/
static void put_prev_task_rt(struct rq *rq, struct task_struct *p, struct task_struct *next)
{
    struct sched_rt_entity *rt_se = &p->rt;
    struct rt_rq *rt_rq = &rq->rt;

    if (on_rt_rq(&p->rt))
        update_stats_wait_start_rt(rt_rq, rt_se);

    update_curr_rt(rq);

    update_rt_rq_load_avg(rq_clock_pelt(rq), rq, 1);

    if (task_is_blocked(p))
        return;
    /*
     * The previous task needs to be made eligible for pushing
     * if it is still active
     */
    if (on_rt_rq(&p->rt) && p->nr_cpus_allowed > 1)
        enqueue_pushable_task(rq, p);
}

static inline void set_next_task_rt(struct rq *rq, struct task_struct *p, bool first)
{
    struct sched_rt_entity *rt_se = &p->rt;
    struct rt_rq *rt_rq = &rq->rt;

    p->se.exec_start = rq_clock_task(rq);
    if (on_rt_rq(&p->rt))
        update_stats_wait_end_rt(rt_rq, rt_se);

    /* The running task is never eligible for pushing */
    dequeue_pushable_task(rq, p);

    if (!first)
        return;

    /*
     * If prev task was rt, put_prev_task() has already updated the
     * utilization. We only care of the case where we start to schedule a
     * rt task
     */
    if (rq->donor->sched_class != &rt_sched_class)
        update_rt_rq_load_avg(rq_clock_pelt(rq), rq, 0);

    rt_queue_push_tasks(rq);
}
